#pragma once

#include "adalog/buffer/Buffer.h"
#include <cstddef>
#include <memory>
#include <atomic>
#include <optional>
#include <mutex>

namespace adalog
{
    class BufferPoolManager;
    class ReadBufferGuard;
    class WriteBufferGuard;

    class BufferHeader
    {
        friend class BufferPoolManager;
        friend class ReadBufferGuard;
        friend class WriteBufferGuard;
    public:
        explicit BufferHeader(std::size_t buffer_id);

    private:
        size_t GetBufferId() const;
        const char* GetDataBegin() const;
        size_t ReadableSize() const;
        void WriteData(const char* data, size_t len);
        size_t WritableSize() const;
        void Reset();

    private:
        const size_t buffer_id_;

        std::mutex rwlatch_;

        /**
         * @brief Buffer的引用计数
         */
        std::atomic<size_t> pin_count_;

        std::unique_ptr<Buffer> buffer_;
    };

    class BufferPoolManager
    {
    public:
        BufferPoolManager(size_t num_buffer);
        ~BufferPoolManager();

        /**
         * @return 缓冲池中Buffer的数量，Buffer的编号从0开始，到Size() - 1结束。
         */
        size_t Size() const;

        /**
         * @brief 获取指定编号的Buffer的读缓冲区。
         * @param buffer_id Buffer的编号，从0开始，到Size() - 1结束。
         * @return 读缓冲区的Guard对象。若指定编号的Buffer不存在，则返回std::nullopt。
         */
        std::optional<ReadBufferGuard> GetReadBuffer(size_t buffer_id);

        /**
         * @brief 获取指定编号的Buffer的写缓冲区。
         * @param buffer_id Buffer的编号，从0开始，到Size() - 1结束。
         * @return 读缓冲区的Guard对象。若指定编号的Buffer不存在，则返回std::nullopt。
         */
        std::optional<WriteBufferGuard> GetWriteBuffer(size_t buffer_id);
        std::optional<size_t> GetPinCount(size_t buffer_id);
        
    private:
        const size_t num_buffers_;

        std::vector<std::shared_ptr<BufferHeader>> buffers_;
    };
} // namespace adalog